﻿//////////////////////////////////////////////////////////////////
//
// Universe\PlanetCell.cs
//
// Copyright (c) 2012 Dan Pike.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Interfaces;
using Utilities;

namespace Universe
{
   internal class PlanetCell
   {
      private static Logger logger_;
      private static TimeSpan treeRespawnAt_ = TimeSpan.MaxValue;

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// Attributes of an active cell
      /// </summary>
      public int X;
      public int Y;
      public Vector3 Normal;
      public short Elevation;
      public CellContent Content;
      public float TreeSize;

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// 
      /// </summary>
      static PlanetCell()
      {
         logger_ = Program.Logger;

         try
         {
            // Get the rate at which trees will grow. Trees are products of the "forest" factory
            IProducerFact forest = Program.Almanac.FindProducer("forest");
            IMaterialFact tree = Program.Almanac.FindMaterial("tree");
            float treesPerTick = forest.GetOutputRate(tree) / (float)Globals.TicksPerDay;
            treeRespawnAt_ = new TimeSpan((long)(1.0 / treesPerTick));
         }
         catch (System.Exception ex)
         {
            logger_.Exception(ex);
         }
      }

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// Returns true if the cell is capable of supporting a forest
      /// </summary>
      /// <param name="normal"></param>
      /// <param name="elevation"></param>
      /// <returns></returns>
      public static bool CanGrowTrees(Vector3 normal, short elevation)
      {
         return (0.7f < normal.Z) && (1800 > elevation);
      }

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// 
      /// </summary>
      public PlanetCell()
      {
         X = Y = 0;
         Content = CellContent.None;
         TreeSize = 0.0f;
      }

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// Implementation of Object
      /// </summary>
      /// <param name="other"></param>
      /// <returns></returns>
      public override bool Equals(object other)
      {
         PlanetCell cell = other as PlanetCell;
         if ((null != cell) && (cell.X == X) && (cell.Y == Y))
         {
            // If the coordinates are the same, then the cell should be the same!
            Debug.Assert(cell.Content == Content);
            Debug.Assert(cell.Elevation == Elevation);
            Debug.Assert(cell.Normal == Normal);
            return true;
         }
         return false;
      }

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// Implementation of Object
      /// </summary>
      /// <param name="entity"></param>
      /// <returns></returns>
      public override int GetHashCode()
      {
         return (X & 0xFFFF) | ((Y & 0xFFFF) << 16);
      }

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// 
      /// </summary>
      /// <param name="planet"></param>
      /// <returns></returns>
      public bool RunNature(Planet planet)
      {
         if (PlanetCell.CanGrowTrees(Normal, Elevation))
         {
            IProducerFact forest = Program.Almanac.FindProducer("forest");
            float growthRate = forest.GetOutputRate(Program.Almanac.FindMaterial("tree"));

         }
         return true;
      }

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// 
      /// </summary>
      /// <param name="planet"></param>
      /// <returns></returns>
      public bool Run(Planet planet)
      {
         try
         {            
            switch (Content)
            {
               case CellContent.Nature:
                  return RunNature(planet);

               case CellContent.None:
               default:
                  throw new InvalidOperationException("cannot run when cell is in state '" + Content + "'");
            }
         }
         catch (System.Exception ex)
         {
            logger_.Exception(ex);
         }
         return false;
      }
   }
}
